<?php

namespace App\Http\Rest\Admin\Resource;

use App\Http\Entities\DddEventEntity;
use Framework\Foundation\Database\FDB;
use Framework\Foundation\Request\ServerRequest;
use Com\Alibaba\Otter\Canal\Protocol\EventType;

class Event
{
    /**
     * @param array $restParams
     * @param $request ServerRequest
     * @throws \Envms\FluentPDO\Exception
     * @return mixed
     */
    public function getList(array $restParams, $request)
    {
        $eventA = $request->getIn('event_a');
        $eventB = $request->getIn('event_b');

        $streamIds = $request->getIn('stream_ids');
        $streamListA = $this->getEventStreamList($eventA);

        if (empty($eventB)) {
            $streamListB = $this->getStreamList(explode(',', $streamIds));
        } else {
            $streamListB = $this->getEventStreamList($eventB);
        }

        // 排序
        $listA = $this->sortStreamList($streamListA);
        $listB = $this->sortStreamList($streamListB);
        // 字段换多行
        $listA = $this->processList($listA);
        $listB = $this->processList($listB);

        // 组合两方事件
        $result = $this->combineList($listA, $listB);

        return $result;
    }

    public function getEventStreamList($eventId)
    {
        $eventInfo = DddEventEntity::getByPk($eventId);
        if (empty($eventInfo)) {
            return [];
        }

        $ids = $eventInfo->streamIds();
        $streamList = FDB::from('ddd_event_stream')
            ->where('ddd_event_stream_id', explode(',', $ids))->fetchAll();

        return $streamList;
    }

    public function getStreamList($streamIds)
    {
        $streamList = FDB::from('ddd_event_stream')
            ->where('ddd_event_stream_id', $streamIds)->fetchAll();
        return $streamList;
    }

    public function processList($streamList)
    {
        foreach ($streamList as $k => $v) {
            $streamList[$k] = $this->processRow($v);
        }

        return $streamList;
    }

    public function processRow($row)
    {
        foreach ($row as $key => $value) {
            if (in_array($key, ['columns', 'update_columns'])) {
                $row[$key] = $this->columnsSeparate($value);
            }
            if (in_array($key, ['update_value'])) {
                $row[$key] = $this->updateValue($value);
            }
        }

        $row['event_name'] = EventType::name($row['event_type']);

        return $row;
    }

    public function columnsSeparate($value)
    {
//        return str_replace(',', ',' . PHP_EOL, $value);
        $array = explode(',', $value);
        $str = '';
        foreach ($array as $k => $v) {
            $str .= $v . PHP_EOL;
        }

        return $str;
    }

    public function updateValue($value)
    {
        $array = json_decode($value, true);
        $str = '';
        foreach ($array as $k => $v) {
            $str .= $k . ':' . $v . PHP_EOL;
        }

        return $str;
    }

    public function sortStreamList($streamList)
    {
        usort($streamList, function ($a, $b) {
            // 有限根据库排
            if ($a['db_name'] > $b['db_name']) {
                return -1;
            }
            if ($a['db_name'] < $b['db_name']) {
                return 1;
            }

            // 其次根据表排
            if ($a['table_name'] > $b['table_name']) {
                return -1;
            }
            if ($a['table_name'] < $b['table_name']) {
                return 1;
            }

            // 最后根据事件类型排序
            if ($a['event_type'] > $b['event_type']) {
                return -1;
            }
            if ($a['event_type'] < $b['event_type']) {
                return 1;
            }

            return 0;
        });

        return $streamList;
    }

    public function combineList($listA, $listB)
    {
        $ret = [];
        foreach ($listA as $aValue) {
            $bRow = $this->extractFromList($listB, $aValue['db_name'], $aValue['table_name']);
            if (empty($bRow)) {
                $bRow = $this->getEmpty();
            }
            $ret[] = [
                'a' => $aValue,
                'b' => $bRow
            ];
        }

        if (!empty($listB)) {
            foreach ($listB as $item) {
                $ret[] = [
                    'a' => $this->getEmpty(),
                    'b' => $item
                ];
            }
        }

        return $ret;
    }

    public function getEmpty()
    {
        return [
            'ddd_event_stream_id' => 0,
            'db_name' => '',
            'table_name' => '',
            'transaction_tag' => '',
            'event_name' => '',
            'event_type' => -100,
            'columns' => '',
            'update_columns' => '',
            'update_value' => '',
            'ignore_column_value' => '',
            'comment' => '',
            'is_deleted' => 0,
            'deleted_at' => '',
            'created_at' => '',
            'updated_at' => '',
        ];
    }

    public function extractFromList(&$listB, $dbName, $tableName)
    {
        foreach ($listB as $k => $v) {
            if ($v['db_name'] == $dbName && $v['table_name'] == $tableName) {
                $row = $v;
                unset($listB[$k]);

                return $row;
            }
        }

        return false;
    }
}
